#include "MyEnemy.h"
#include "MyEnemies.h"
#include "MyShot.h"
#include "MyUniversal.h"
#include "MyDefinitions.h"
#include "MyGame.h"
#include "MyEngine.h"
#include "MyShots.h"
#include "MyPlayer.h"
#include "MyMessages.h"

MyShot::MyShot(){}
MyShot::~MyShot(){}
MyShot::MyShot(double _pos_x, double _pos_y, double initial_angle, shotType* _thisShotType, MyShots* _parent, int _owner, int _dmg)
{
	first = 1;
	init_shot(_pos_x,_pos_y,initial_angle,_thisShotType, _parent, _owner, _dmg);
}
void MyShot::init_shot(double _pos_x, double _pos_y, double initial_angle, shotType* _thisShotType, MyShots* _parent, int _owner, int _dmg)
{	
	//set the position == starting position == old possition
	owner = _owner;
	pos_x = _pos_x; 
	pos_y = _pos_y; 
	starting_x_pos = _pos_x;		//used for calculating the range of shot
	starting_y_pos = _pos_y;		//used for calculating the right elevation
	old_x_pos = _pos_x;				//old x/y values used for the cover rectangle
	old_y_pos = _pos_y;
	dmg = _dmg;

	//calc the speeds from the initial speed
	speed_x = _thisShotType->speed_initial * cos(initial_angle);
	//security, so we dont divide by 0 accidentally
	if (!speed_x) speed_x = 0.0001;
	speed_y = _thisShotType->speed_initial * sin(initial_angle); 
	//angle of the shot 
	angle = initial_angle;
	rotationAngle = initial_angle;
	//calculations for further use
	range = (_thisShotType->speed_initial * _thisShotType->speed_initial * sin(2*initial_angle)/GRAVITY);
	flightDuration = range / speed_x;

	if (angle > M_PI*0.5) 
	{
		//sign correction for the III quadrant
		range *= -1;		
		//	flightDuration *= -1;		
	}
	//type of this shot
	thisShotType = _thisShotType;
	//pointer to the parent MyShots class
	parent = _parent;
	//state of the shot
	shotState = SS_FLY;
	//duration of shot laying on ground
	layDuration = 0;
}
shotType* MyShot::getType() { return thisShotType; }
bool MyShot::move_shot(int t)
{
	old_x_pos = pos_x;
	old_y_pos = pos_y;	

	double _t = t/100.0;
	//decide what state is the shot in
	switch (shotState)	
	{
	case SS_FLY: 
	{
		if (thisShotType->ballistic)	//ballistic curve for trajectory
		{
			/*******shooting right*********/
			if (angle < (M_PI * 0.5)) 
			{		
				//update pox_x, pos_y >> both are abs positions on screen
				//units of speed_x/y are px/ms, units of _t are ms, units of pos_x are px
				pos_x += speed_x * _t;							//x = v_x * t
				pos_x_rel = pos_x - starting_x_pos;				//shot moving to the right	
				pos_y = starting_y_pos - pos_x_rel * tan(angle) +	//y = y_0 - x tan A + 0.5*g*x^2/v_x^2 
					(GRAVITY*pos_x_rel*pos_x_rel*0.5/speed_x)/speed_x;
				//calculate the angle of rotation in degrees, add correction
				rotationAngle = atan2((pos_y-old_y_pos),(old_x_pos - pos_x))*180/M_PI + 180;
			}
			/*******shooting left*******/
			else
			{	
				//almost as before, just x sign is inverted
				pos_x += speed_x * _t;					
				pos_x_rel = starting_x_pos - pos_x;						
				pos_y = starting_y_pos + pos_x_rel * tan(angle)  + (GRAVITY*pos_x_rel*pos_x_rel*0.5/speed_x)/speed_x;
				//calculate the angle of rotation in degrees, add correction
				rotationAngle = atan2((pos_y-old_y_pos),(old_x_pos - pos_x))*180/M_PI + 180;
			}
		}
		else	//straight trajectory = spells
		{
			/*******shooting spell right*********/
			if (angle < (M_PI * 0.5)) 
			{		
				//update pox_x, pos_y >> both are abs positions on screen		
				pos_x += thisShotType->speed_initial * _t;		//x = v_x * t
				pos_x_rel = pos_x - starting_x_pos;				//shot moving to the right		
				layDuration += t;				
				rotationAngle = 1;
			}
			/*******shooting spell left*******/
			else
			{
				//almost as before, just x sign is inverted
				pos_x -= thisShotType->speed_initial * _t;					
				pos_x_rel = starting_x_pos - pos_x;						
				layDuration += t;
				rotationAngle = 0;
			}
		}
	//out of screen check, if scroll is enables > adjust
	if ((pos_x > FIELD_W) || (pos_x < 0)) 
	{
		#ifdef _DEBUG
		cout << "shot out of screen" << endl;
		#endif
		//return true if the shot is out of screen & must be destroyed
		return true;	
	}
	
	//possible problem when dealing with shots thisShotType->shot_h > PLAYER_H*0.6
	if ( pos_y > starting_y_pos + PLAYER_H * 0.60 - thisShotType->shot_h)			//landed
	{
		//set the state to SS_LAY
		shotState = SS_LAY;
		//the duration is set to 0 during init
		return false;
	}
	break;
	}
	//shot has landed and is laying on the ground
	case SS_LAY:{
		layDuration += int(_t*1000);
		//return true if the shot layed long enough & must be destroyed		
		if (layDuration > LAY_MAX_DURATION) return true;
		break;
	}
	} //end of switch

	//drawing, if true is returned, shot must be deleted > collided with stg
	if(draw_shot()) return true;
	return false;	
}
bool MyShot::draw_shot()
{
	//temp for a shot rect to get the right sprite, used in collision detection and drawing
	SDL_Rect *tmp1 = make_rect(
		decide_frame_by_angle(rotationAngle),
		thisShotType->pos_in_sheet*thisShotType->shot_h,
		thisShotType->shot_w,
		thisShotType->shot_h);

	//temp for a shot position on screen
	SDL_Rect *tmp2 = make_rect(int(pos_x), int(pos_y), int(thisShotType->shot_w), SHOT_H);

	//draw the shot; if spell
	if (thisShotType->mana_consume) 
	{
		tmp1->y -= ST_SHOT_COUNT*thisShotType->shot_h;
		SDL_BlitSurface(parent->spellSheet, tmp1, parent->parent->parent->screen, tmp2);
	}
	else 
		SDL_BlitSurface(parent->shotSheet, tmp1, parent->parent->parent->screen, tmp2);
	//delete
	delete(tmp1);
	delete(tmp2);	
	if(collide()) return true;
	return false;
}
int MyShot::decide_frame_by_angle(double a) {
	//if the shot is ballistic, the position in sheet is calculated as angle/10*w
	if (thisShotType->ballistic) 
	{
		return (((int)a)/10)*thisShotType->shot_w; 
	}
	/* else we are shooting straight and the position is either left or right,
	 * the layduaaration variable will indicate the state and the angle will tell
	 * us in which half of shot sheet this sprite is
	 * rotation angle is used as marker RIGHT */
	else 
	{
		if (a) //in the second half of the sheet, add phase_count*shot_w to the result
		{
			int x = ((layDuration/100)%(thisShotType->phase_count/2) + thisShotType->phase_count/2)*thisShotType->shot_w;
			return x;
		}
		else 
		{
			int x = ((layDuration/100)%(thisShotType->phase_count/2)) * thisShotType->shot_w; 
			return x;
		}
	}
}
bool MyShot::collide()
{	
	if (shotState == SS_FLY)
	{
		int temp_int=0;
		//temp for the Shot Rect
		SDL_Rect * tmpSR;
		//this compound if will decide what half-quad is the shot in (due to it's rotation) and return the hit rect
			 if ((rotationAngle < 45)||(rotationAngle > 315)) tmpSR = make_rect(int(pos_x + 6), int(pos_y + 3), 4, 4);
		else if (rotationAngle < 135) tmpSR = make_rect(int(pos_x + 3), int(pos_y + 6), 4, 4);
		else if (rotationAngle < 225) tmpSR = make_rect(int(pos_x + 1), int(pos_y + 3), 4, 4);
		else tmpSR = make_rect(int(pos_x + 3), int(pos_y + 1), 4, 4);

		// hit zone collision detection, pixel perfect too cpu&ram consuming - player/shot
		if(temp_int = collide_player(tmpSR)) 
		{
			parent->parent->actPlayer->loose_life(temp_int);
			delete(tmpSR);
			return true;
		}
		// hit zone collision detection, pixel perfect too cpu&ram consuming - enemies/shot
		if(temp_int = collide_enemies(tmpSR)) 
		{			
			//give player exp
			parent->parent->actPlayer->set_exp_d(temp_int);
			delete(tmpSR);
			return true;
		}
		delete(tmpSR);
		return false;
	}
	return false;
}
int MyShot::collide_player(SDL_Rect* _tmpSR)
{
	//get the hit rect from player object
	SDL_Rect * tmpPR = parent->parent->actPlayer->get_hit_zone();

	if ((owner!=OT_PLAYER)&&(SDL_CollideBoundingBox(_tmpSR,tmpPR))) 
	{
		delete(tmpPR);
		//return the amount of dmg to deal to the player
		return dmg;
	}	
	else
	{
		delete(tmpPR);
		return 0;
	}
}
int MyShot::collide_enemies(SDL_Rect* _tmpSR)
{
	SDL_Rect * tmpER;
	std::list<MyEnemy>::iterator i;
	//cycle through all enemies and check the collision
	for (i = parent->parent->actEnemies->enemySwarm.begin(); i != parent->parent->actEnemies->enemySwarm.end();)
	{
		//set the temp variable for enemy rect
		tmpER = i->get_hit_zone();

		//test the collision between enemy and shot
		if ((owner!=OT_ENEMY)&&(SDL_CollideBoundingBox(_tmpSR, tmpER))) // true = hit 
		{
			//if the enemy's life is 0 or less, return the amount of exp player will receive -- enemy was just killed			
			if(i->set_life(i->get_life() - this->dmg))
			{				
				//backup the exp player will receive, 
				int tmpint = i->getType()->exp;	
				parent->parent->actPlayer->enemy_killed();
				parent->parent->actPlayer->set_money_d(i->getType()->cash_for_kill);

				//display message of enemy kill
				parent->parent->actMessages->add_border_text_message(3000, "Enemy Killed!", parent->parent->color_red);
				char* tempchar = new char[4];
				sprintf(tempchar, "+%d", i->getType()->cash_for_kill);
				parent->parent->actMessages->add_text_message(250, tmpER->x + tmpER ->w/2, tmpER->y-10, tmpER->x+tmpER->w/2, tmpER->y-40, tempchar, 
					parent->parent->color_exp1,parent->parent->color_exp1);
				delete(tempchar);
				delete (tmpER);
				//delete the killed enemy
				parent->parent->actEnemies->enemySwarm.erase(i++);

				//return the exp for player
				return tmpint;
			}
			//enemy was hit, but not killed
			else
			{	
				//give player 1 exp for hit
				return 1;
			}
		}
		else 
		{
			//free the temp rect for enemy hit zone
			delete (tmpER);
			//go to next enemy
			i++;
		}
	}
	return 0; //gone through all the enemies, none collided
}
